﻿using System.Linq;
using System.Collections.Generic;

namespace Godot.core
{
    using SysMethodInfo = System.Reflection.MethodInfo;

    public partial class Translation : Resource
    {
        public Translation()
        {
            __locale = "en";
            __translation_map = new Dictionary<StringName, StringName>();
        }

        public string get_locale()
        {
            return __locale;
        }

        public void set_locale(string p_locale) 
        {
	        //ERR_EXPLAIN("Invalid Locale: "+p_locale);
            if (!TranslationServer.is_valid_locale(p_locale))
                return;	        
            __locale = p_locale;
        }

        public void add_message(StringName p_src_text, StringName p_xlated_text ) 
        {
	        __translation_map[p_src_text] = p_xlated_text;
        }

        public StringName get_message(StringName p_src_text) 
        {
            StringName E = null;
            if(__translation_map.TryGetValue(p_src_text, out E))
                return null;
            return E;
        }

        public void erase_message(StringName p_src_text) 
        {
	        __translation_map.Remove(p_src_text);
        }

        public void get_message_list(ref List<StringName> r_messages)
        {
	        foreach(KeyValuePair<StringName,StringName> E in __translation_map) 
            {
		        r_messages.Add(E.Key);
	        }
        }

        protected List<string> _get_message_list()
        {
	        List<string> msgs = Enumerable.Repeat<string>("", __translation_map.Count).ToList();
	        int idx = 0;
	        foreach(KeyValuePair<StringName, StringName> E in __translation_map) 
            {
		        msgs[idx] = E.Key;
		        idx += 1;
	        }
	        return msgs;
        }

        protected void _set_messages(List<string> p_messages)
        {
	        int msg_count = p_messages.Count;
	        
            if(msg_count % 2 != 0)
                return;

	        for(int i = 0; i < msg_count; i += 2) 
            {
		        add_message( p_messages[i + 0], p_messages[i + 1] );
	        }
        }

        protected List<string> _get_messages()
        {
            List<string> msgs = Enumerable.Repeat<string>("", __translation_map.Count * 2).ToList();
	        int idx = 0;
	        foreach(KeyValuePair<StringName, StringName> E in __translation_map) 
            {
		        msgs[idx + 0] = E.Key;
		        msgs[idx + 1] = E.Value;
		        idx += 2;
	        }

	        return msgs;
        }

        protected static new void _bind_methods() 
        {
	        ObjectTypeDB.bind_method(_MD("set_locale","locale"), typeof(Translation).GetMethod("set_locale", Misc.BindingFlags_Greedy));
	        ObjectTypeDB.bind_method(_MD("get_locale"), typeof(Translation).GetMethod("get_locale", Misc.BindingFlags_Greedy));
	        ObjectTypeDB.bind_method(_MD("add_message","src_message","xlated_message"), typeof(Translation).GetMethod("add_message", Misc.BindingFlags_Greedy));
	        ObjectTypeDB.bind_method(_MD("get_message","src_message"),typeof(Translation).GetMethod("get_message", Misc.BindingFlags_Greedy));
	        ObjectTypeDB.bind_method(_MD("erase_message","src_message"), typeof(Translation).GetMethod("erase_message", Misc.BindingFlags_Greedy));
	        ObjectTypeDB.bind_method(_MD("get_message_list"), typeof(Translation).GetMethod("_get_message_list" , Misc.BindingFlags_Greedy));
	        ObjectTypeDB.bind_method(_MD("_set_messages"), typeof(Translation).GetMethod("_set_messages", Misc.BindingFlags_Greedy));
	        ObjectTypeDB.bind_method(_MD("_get_messages"), typeof(Translation).GetMethod("_get_messages", Misc.BindingFlags_Greedy));

            ObjectTypeDB.add_property(get_type_static(), new PropertyInfo(Variant.Type.STRING_ARRAY, "messages", PropertyHint.PROPERTY_HINT_NONE, "", (int)PropertyUsageFlags.PROPERTY_USAGE_NOEDITOR), "_set_messages", "_get_messages");
	        ObjectTypeDB.add_property(get_type_static(), new PropertyInfo(Variant.Type.STRING, "locale"), "set_locale", "get_locale");
        }

        private Dictionary<StringName, StringName> __translation_map;
        private string __locale;
    }

    public partial class Translation
    {
        #region OBJ_TYPE( Translation, Resource )
        public override string get_type() { return "Translation"; }

        public override string get_save_type() { return get_type(); } //type stored when saving

        public override StringName get_type_name() { return (StringName)get_type_static(); }

        public override bool is_type(string p_type) { return (p_type == "Translation") ? true : base.is_type(p_type); }

        protected override void _initialize_typev() { initialize_type(); }

        protected override bool _setv(StringName p_name, Variant p_property)
        {
            if (base._setv(p_name, p_property))
                return true;

            if (typeof(Translation).GetMethod("_set") != typeof(Resource).GetMethod("_set"))
            {
                return _set(p_name, p_property);
            }

            return false;
        }

        protected override bool _getv(StringName p_name, ref Variant r_property)
        {
            if (typeof(Translation).GetMethod("_get") != typeof(Resource).GetMethod("_get"))
            {
                if (_get(p_name, ref r_property))
                    return true;
            }

            return base._getv(p_name, ref r_property);
        }

        protected override void _get_property_listv(ref List<PropertyInfo> p_list, bool p_reversed)
        {
            if (!p_reversed)
            {
                base._get_property_listv(ref p_list, p_reversed);
            }

            p_list.Add(new PropertyInfo(Variant.Type.NIL, get_type_static(), PropertyHint.PROPERTY_HINT_NONE, "", (int)PropertyUsageFlags.PROPERTY_USAGE_CATEGORY));

            if (!_is_gpl_reversed())
                ObjectTypeDB.get_property_list("Translation", ref p_list, true);

            if (typeof(Translation).GetMethod("_get_property_list") != typeof(Resource).GetMethod("_get_property_list"))
            {
                _get_property_list(ref p_list);
            }

            if (_is_gpl_reversed())
                ObjectTypeDB.get_property_list("Translation", ref p_list, true);

            if (p_reversed)
            {
                base._get_property_listv(ref p_list, p_reversed);
            }
        }

        protected override void _notificationv(int p_notification, bool p_reversed)
        {
            if (!p_reversed)
                base._notificationv(p_notification, p_reversed);

            if (typeof(Translation).GetMethod("_notification") != typeof(Resource).GetMethod("_notification"))
            {
                _notification(p_notification);
            }

            if (p_reversed)
                base._notificationv(p_notification, p_reversed);
        }

        public static new string get_type_static() { return "Translation"; }

        public static new string get_parent_type_static() { return Resource.get_type_static(); }

        public static new void get_inheritance_list_static(ref List<string> r_inheritance_list)
        {
            Resource.get_inheritance_list_static(ref r_inheritance_list);
            r_inheritance_list.Add(get_type_static());
        }

        public static new string get_category_static()
        {
            string category = Resource.get_category_static();
            if (typeof(Translation).GetMethod("_get_category") != typeof(Resource).GetMethod("_get_category"))
            {
                if (category != "")
                    category += "/";
                category += _get_category();
            }
            return category;
        }

        public static new string inherits_static() { return "Resource"; }

        public static new void get_valid_parents_static(ref List<string> p_parents)
        {
            if (typeof(Translation).GetMethod("_get_valid_parents_static") != typeof(Resource).GetMethod("_get_valid_parents_static"))
            {
                Translation._get_valid_parents_static(ref p_parents);
            }

            Resource.get_valid_parents_static(ref p_parents);
        }

        public static new void initialize_type()
        {
            if (__initialized)
                return;
            Resource.initialize_type();
            ObjectTypeDB._add_type<Translation>();

            SysMethodInfo cls_bind = typeof(Translation).GetMethod("_bind_methods", Misc.BindingFlags_Greedy);
            SysMethodInfo par_bind = typeof(Resource).GetMethod("_bind_methods", Misc.BindingFlags_Greedy);
            if (cls_bind != par_bind)
                cls_bind.Invoke(null, null);
            __initialized = true;
        }

        private static bool __initialized = false;
        #endregion

        #region RES_BASE_EXTENSION("xl")
        public static new void register_custom_data_to_otdb()
        {
            ObjectTypeDB.add_resource_base_extension("xl", get_type_static());
        }

        public virtual string get_base_extension()
        {
            return "xl";
        }
        #endregion
    }
}
